package com.simp.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.simp.costant.Constant;
import com.simp.entity.SysLogEntity;
import com.simp.utils.*;
import com.simp.vo.ReflectVo;
import com.simp.vo.TokenInfoVo;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author pan.shun
 * @since 2022/3/24 10:52
 */

@Slf4j
@Aspect  // 使用@Aspect注解声明一个切面
@Component
public class SysLogAspect {


    @Pointcut("@annotation(com.simp.aop.SysLog)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        long startTime = System.currentTimeMillis();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SysLog sysLog = method.getAnnotation(SysLog.class);

        String eventContent = sysLog.value();

        SysLogEntity sysLogEntity = new SysLogEntity();
        Object result = null;
        try {
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

            sysLogEntity.setIpAddress(IPUtils.getIp(request));
            String path = request.getRequestURI();
            String contextPath = request.getContextPath();
            if (!StringUtils.isEmpty(contextPath) && path.startsWith(contextPath)) {
                path = path.substring(contextPath.length());
            }
            sysLogEntity.setRequestUri(path);


            String agentStr = request.getHeader("User-Agent");

            if (!StringUtils.isEmpty(agentStr)) {
                UserAgent agent = UserAgent.parseUserAgentString(agentStr);
                sysLogEntity.setBrowserName(agent.getBrowser().getName());
                sysLogEntity.setDeviceName(agent.getOperatingSystem().getName());
                agentStr = org.apache.commons.lang3.StringUtils.substring(agentStr, 0, 255);
                sysLogEntity.setUserAgent(agentStr);
            }

            TokenInfoVo jwtClaimsDetailByRequest = JwtUtil.getJwtClaimsDetailByRequest(request);
            String userName = jwtClaimsDetailByRequest.getUserName();
            String userId = jwtClaimsDetailByRequest.getUserId();
            sysLogEntity.setUserName(userName);
            sysLogEntity.setUserId(userId);

            result = joinPoint.proceed();

            boolean flag = sysLog.addOrUpdate();
            if (flag) {
                Object[] args = joinPoint.getArgs();
                if (args.length != 0) {
                    ReflectVo convert = BeanConvertUtils.convert(args[0], ReflectVo.class);
                    if (convert != null && !StringUtils.isEmpty(convert.getId())) {
                        eventContent += "修改";
                    } else {
                        eventContent += "新增";
                    }
                    if (convert != null && !StringUtils.isEmpty(convert.getName())) {
                        eventContent += " ,名称为: " + convert.getName();
                    }
                    if (convert != null && !StringUtils.isEmpty(convert.getConfigKey())) {
                        eventContent += " ,键名为: " + convert.getConfigKey();
                    }
                }
            }
            sysLogEntity.setStatus(Constant.LOG_STATUS.SUCCESS);
            sysLogEntity.setActionEvent(Constant.LOG_EVENT.OTHER);
            sysLogEntity.setEventContent(eventContent);
        } catch (Throwable throwable) {
            sysLogEntity.setStatus(Constant.LOG_STATUS.FAIL);
            sysLogEntity.setException(ExceptionUtils.print(throwable));
            sysLogEntity.setActionEvent(Constant.LOG_EVENT.ERROR);
            sysLogEntity.setEventContent(eventContent);
        } finally {
            log.info("日志记录完毕, sysLogEntity :{}", sysLogEntity.toString());
            BeanServiceUtils.saveLog(sysLogEntity, startTime);
        }
        return result;
    }
}
